home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #1 / Amiga Plus CD - 2000 - No. 1.iso / Tools / Text / Edit / GoldED-Demo / installdata / golded / developer / api / examples / timer / funcs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-03  |  10.1 KB  |  395 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  timer.api ©1999 Dietmar Eilert
  4.  
  5.  API plug-in. This example demonstrates message port handling. Dice:
  6.  
  7.  DMAKE
  8.  
  9.  -------------------------------------------------------------------------------
  10.  
  11. */
  12.  
  13. #include "defs.h"
  14.  
  15. /// "prototypes"
  16.  
  17. // library functions
  18.  
  19. Prototype LibCall struct APIClient *APIMountClient(__A0 struct APIMessage *, __A1 char *);
  20. Prototype LibCall void              APICloseClient(__A0 struct APIClient *,  __A1 struct APIMessage *);
  21. Prototype LibCall void              APIBriefClient(__A0 struct APIClient *,  __A1 struct APIMessage *);
  22. Prototype LibCall void              APIFree       (__A0 struct APIClient  *, __A1 struct APIOrder   *);
  23.  
  24. // private functions
  25.  
  26. Prototype struct HostContext       *AddHost       (struct Task *);
  27. Prototype void                      AddTimerEvent (struct HostContext *);
  28. Prototype ULONG                     Dispatch      (struct APIClient *, struct APIMessage *);
  29. Prototype struct HostContext       *FindContext   (struct Task *);
  30. Prototype void                      RemoveHost    (struct HostContext *);
  31.  
  32. ///
  33. /// "globals"
  34.  
  35. struct List HostList;
  36.  
  37. ///
  38. /// "library functions"
  39.  
  40. LibCall struct APIClient *
  41. APIMountClient(__A0 struct APIMessage *apiMsg, __A1 char *args)
  42. {
  43.     struct PlugInContext *plugInContext;
  44.  
  45.     if (plugInContext = (struct PlugInContext *)AllocVec(sizeof(struct PlugInContext), MEMF_CLEAR | MEMF_PUBLIC)) {
  46.  
  47.         struct HostContext *hostContext;
  48.         struct Task        *task;
  49.  
  50.         task = FindTask(NULL);
  51.  
  52.         // find context of host task (or allocate new context if a new host starts using this plug-in)
  53.  
  54.         hostContext = FindContext(task);
  55.  
  56.         if (hostContext == NULL)
  57.  
  58.             hostContext = AddHost(task);
  59.  
  60.         if (hostContext) {
  61.  
  62.             // track number of plug-in instances used by host task
  63.  
  64.             ++hostContext->OpenCount;
  65.  
  66.             // build plug-in description for host
  67.  
  68.             plugInContext->APIClient.api_APIVersion = API_INTERFACE_VERSION;
  69.             plugInContext->APIClient.api_Version    = 1;
  70.             plugInContext->APIClient.api_Name       = "Timer";
  71.             plugInContext->APIClient.api_Info       = "API example";
  72.             plugInContext->APIClient.api_Commands   = NULL;
  73.             plugInContext->APIClient.api_Serial     = 0;
  74.             plugInContext->APIClient.api_Classes    = API_CLASS_SYSTEM;
  75.             plugInContext->APIClient.api_Area       = NULL;
  76.             plugInContext->APIClient.api_Signals    = 1L<<(hostContext->TimerPort->mp_SigBit);
  77.  
  78.             // remember host context for this instance
  79.  
  80.             plugInContext->HostContext = hostContext;
  81.         }
  82.         else {
  83.  
  84.             FreeVec(plugInContext);
  85.  
  86.             plugInContext = NULL;
  87.         }
  88.     }
  89.  
  90.     return((struct APIClient *)plugInContext);
  91. }
  92.  
  93. LibCall void
  94. APICloseClient(__A0 struct APIClient *handle, __A1 struct APIMessage *apiMsg)
  95. {
  96.     if (handle) {
  97.  
  98.         struct HostContext *context;
  99.  
  100.         // find host context for this plug-in instance
  101.  
  102.         context = ((struct PlugInContext *)handle)->HostContext;
  103.  
  104.         // check open count (closing last instance used by this task ?)
  105.  
  106.         if (context->OpenCount > 1) {
  107.  
  108.             --context->OpenCount;
  109.         }
  110.         else
  111.             RemoveHost(context);
  112.  
  113.         FreeVec(handle);
  114.     }
  115. }
  116.  
  117. LibCall void
  118. APIBriefClient(__A0 struct APIClient *handle, __A1 struct APIMessage *apiMsg)
  119. {
  120.     struct APIMessage *msg;
  121.  
  122.     // handle host's command notify
  123.  
  124.     for (msg = apiMsg; msg; msg = msg->api_Next) {
  125.  
  126.         if (msg->api_State == API_STATE_NOTIFY) {
  127.  
  128.             switch (msg->api_Class) {
  129.  
  130.                 case API_CLASS_SYSTEM:
  131.  
  132.                     switch (msg->api_Action) {
  133.  
  134.                         case API_ACTION_SIGNAL:
  135.  
  136.                             {
  137.                                 struct HostContext *context;
  138.  
  139.                                 // find host task context for this plug-in instance
  140.  
  141.                                 if (context = ((struct PlugInContext *)handle)->HostContext) {
  142.  
  143.                                     ULONG signal = 1L<<(context->TimerPort->mp_SigBit);
  144.  
  145.                                     // is this our signal ?
  146.  
  147.                                     if (signal & (ULONG)apiMsg->api_Data) {
  148.  
  149.                                         struct timerequest *timerequest;
  150.  
  151.                                         // process event
  152.  
  153.                                         msg->api_Error = Dispatch(handle, apiMsg);
  154.  
  155.                                         // the first plug-in instance seeing this signal gets the actual message and reinitializes the timer)
  156.  
  157.                                         if (timerequest = (struct timerequest *)GetMsg(context->TimerPort)) {
  158.  
  159.                                             FreeVec(timerequest);
  160.  
  161.                                             // no pending timer requests for this host
  162.  
  163.                                             context->IOPending = NULL;
  164.  
  165.                                             // restart timer for this host
  166.  
  167.                                             AddTimerEvent(context);
  168.                                         }
  169.                                     }
  170.                                 }
  171.                             }
  172.  
  173.                             break;
  174.  
  175.                         default:
  176.  
  177.                             msg->api_Error = API_ERROR_UNKNOWN;
  178.                     }
  179.  
  180.                     break;
  181.  
  182.                 default:
  183.  
  184.                     msg->api_Error = API_ERROR_UNKNOWN;
  185.             }
  186.         }
  187.     }
  188. }
  189.  
  190. LibCall void
  191. APIFree(__A0 struct APIClient *handle, __A1 struct APIOrder *apiOrder)
  192. {
  193.     // no ressources to be freed
  194. }
  195.  
  196. ///
  197. /// "private"
  198.  
  199. /* -------------------------------- FindContext --------------------------------
  200.  
  201.  Find context for this task. A "context" is a structure allocated for each host
  202.  task (ie. each GoldED task) using this plug-in. It holds task-specific data.
  203.  The concept of contexts is used because the resources used by this plug-in
  204.  (specifically message ports) may only be allocated and used on a per-task
  205.  basis undrer AmigaOS3.
  206.  
  207. */
  208.  
  209. struct HostContext *
  210. FindContext(task)
  211.  
  212. struct Task *task;
  213. {
  214.     struct HostContext *context;
  215.  
  216.     for (context = (struct HostContext *)HostList.lh_Head; context->Node.ln_Succ; context = (struct HostContext *)context->Node.ln_Succ)
  217.  
  218.         if (context->Task == task)
  219.  
  220.             return(context);
  221.  
  222.     return(NULL);
  223. }
  224.  
  225.  
  226. /* ---------------------------------- AddHost ----------------------------------
  227.  
  228.  Add host to list of registered hosts, allocate resources (e.g. one message
  229.  port per host) and start the timer. Usually a plug-in is used by one host
  230.  only but theoretically plug-ins can be used by multiple hosts simultaneously.
  231.  
  232. */
  233.  
  234. struct HostContext *
  235. AddHost(task)
  236.  
  237. struct Task *task;
  238. {
  239.     struct HostContext *context;
  240.  
  241.     if (context = (struct HostContext *)AllocVec(sizeof(struct HostContext), MEMF_CLEAR | MEMF_PUBLIC)) {
  242.  
  243.         context->Task = task;
  244.  
  245.         if (context->TimerPort = CreateMsgPort()) {
  246.  
  247.             if (context->TimeRequest = (struct timerequest *)CreateExtIO(context->TimerPort, sizeof(struct timerequest))) {
  248.  
  249.                 if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)context->TimeRequest, 0) == 0) {
  250.  
  251.                     AddTail(&HostList, &context->Node);
  252.  
  253.                     // start timer (create initial timer request)
  254.  
  255.                     AddTimerEvent(context);
  256.  
  257.                     return(context);
  258.                 }
  259.  
  260.                 DeleteExtIO((struct IORequest *)context->TimeRequest);
  261.             }
  262.  
  263.             DeleteMsgPort(context->TimerPort);
  264.         }
  265.  
  266.         FreeVec(context);
  267.     }
  268.  
  269.     return(NULL);
  270. }
  271.  
  272.  
  273. /* -------------------------------- RemoveHost ---------------------------------
  274.  
  275.  Remove host from list of registered hosts (stop the timer for this host).
  276.  
  277. */
  278.  
  279. void
  280. RemoveHost(context)
  281.  
  282. struct HostContext *context;
  283. {
  284.     Remove(&context->Node);
  285.  
  286.     if (context->IOPending) {
  287.  
  288.         AbortIO((struct IORequest *)context->IOPending);
  289.  
  290.         WaitIO ((struct IORequest *)context->IOPending);
  291.  
  292.         FreeVec(context->IOPending);
  293.     }
  294.  
  295.     if (context->TimeRequest) {
  296.  
  297.         CloseDevice((struct IORequest *)context->TimeRequest);
  298.  
  299.         DeleteExtIO((struct IORequest *)context->TimeRequest);
  300.     }
  301.  
  302.     if (context->TimerPort) {
  303.  
  304.         struct Message *msg;
  305.  
  306.         while (msg = (struct Message *)GetMsg(context->TimerPort))
  307.  
  308.             ReplyMsg(msg);
  309.  
  310.         DeleteMsgPort(context->TimerPort);
  311.     }
  312.  
  313.     FreeVec(context);
  314. }
  315.  
  316.  
  317. /* ----------------------------------- AddTimerEvent ---------------------------
  318.  
  319.  Send timer event (wait one second)
  320.  
  321. */
  322.  
  323. void
  324. AddTimerEvent(context)
  325.  
  326. struct HostContext *context;
  327. {
  328.     // no timer event pending ?
  329.  
  330.     if (context->IOPending == NULL) {
  331.  
  332.         if (context->IOPending = (struct timerequest *)AllocVec(sizeof(struct timerequest), MEMF_ANY | MEMF_PUBLIC)) {
  333.  
  334.             // initialize IORequest
  335.  
  336.             *context->IOPending = *context->TimeRequest;
  337.  
  338.             // wait for one second
  339.  
  340.             context->IOPending->tr_node.io_Command = TR_ADDREQUEST;
  341.             context->IOPending->tr_time.tv_secs    = 1;
  342.  
  343.             SendIO((struct IORequest *)context->IOPending);
  344.         }
  345.     }
  346. }
  347.  
  348.  
  349. /* --------------------------------- Dispatch ----------------------------------
  350.  
  351.  Dispatch timer even. We do NOT consume this event (by setting apiMsg->api_State
  352.  to API_STATE_CONSUMED) so that other instances of this plug-in using the same
  353.  timer can see the event, too.
  354.  
  355. */
  356.  
  357. ULONG
  358. Dispatch(handle, apiMsg)
  359.  
  360. struct APIClient  *handle;
  361. struct APIMessage *apiMsg;
  362. {
  363.     static UBYTE *quotes[] = {
  364.  
  365.         "Cheer up, Brian. You know what they say."
  366.         "Some things in life are bad,",
  367.         "They can really make you mad.",
  368.         "Other things just make you swear and curse.",
  369.         "When you're chewing on life's grissle,",
  370.         "Don't grumble, give a whistle.",
  371.         "And this'll help things turn out for the best,"
  372.         "And...",
  373.         "Always look on the bright side of life",
  374.         "Always look on the bright side of life",
  375.         NULL
  376.     };
  377.  
  378.     static UWORD next = 0;
  379.  
  380.     // set status text
  381.  
  382.     apiMsg->api_Status = quotes[next];
  383.  
  384.     // activate next string
  385.  
  386.     if (quotes[++next] == NULL)
  387.  
  388.         next = 0;
  389.  
  390.     return(API_ERROR_OK);
  391. }
  392.  
  393.  
  394. ///
  395.